<template>
  <el-form
    ref="ruleForm"
    :model="userInputDataForm"
    label-width="120px"
    :rules="rules"
    class="form-widget"
  >
    <template v-for="(field, key) in userInputDataForm" :key="key">
      <!-- input -->
      <el-form-item
        v-if="TYPE_TO_INPUT_WIDGETS[field.Type] === FORM_WIDGETS.INPUT"
        :label="field.Translation == null ? key : field.Translation"
        :prop="key"
      >
        <el-input v-model="userInputDataForm[key].Value" size="small">
          <template #suffix>
            <el-popover
              effect="dark"
              placement="top-end"
              :width="200"
              :show-after="500"
              v-if="field.Help != null"
            >
              <p>{{ field.Help }}</p>
              <template #reference>
                <el-icon>
                  <question-filled />
                </el-icon>
              </template>
            </el-popover>
          </template>
        </el-input>
      </el-form-item>
      <el-form-item
        v-else-if="
          TYPE_TO_INPUT_WIDGETS[field.Type] === FORM_WIDGETS.CHOICE_LIST
        "
        :label="key"
        :prop="key"
      >
        <el-select v-model="userInputDataForm[key].Value">
          <el-option
            v-for="item in field.Meta"
            :key="item.Value"
            :label="item.Visual"
            :value="item.Value"
          >
          </el-option>
        </el-select>
      </el-form-item>
      <!-- time -->
      <el-form-item
        v-else-if="TYPE_TO_INPUT_WIDGETS[field.Type] == FORM_WIDGETS.DATETIME"
        :label="key"
        :prop="key"
      >
        <el-date-picker
          v-model="userInputDataForm[key].Value"
          type="datetime"
          placeholder="选择日期时间"
        ></el-date-picker>
      </el-form-item>
      <!-- file 需要完善action -->
      <el-form-item
        v-else-if="TYPE_TO_INPUT_WIDGETS[field.Type] == FORM_WIDGETS.FILE"
        :label="key"
        :prop="key"
      >
        <el-upload>
          <el-button type="primary">点击上传</el-button>
        </el-upload>
      </el-form-item>
      <!-- json 包含'+', 输入key value '-' -->
      <template
        v-else-if="TYPE_TO_INPUT_WIDGETS[field.Type] == FORM_WIDGETS.JSON"
      >
        <el-form-item :label="key">
          <el-button icon="el-icon-plus" @click="addNewPair(field)" circle />
        </el-form-item>
        <template v-if="field.Value != null && field.Value !== []">
          <el-form-item v-for="(pair, index) in field.Value" :key="pair[0]">
            <el-col :span="9" class="md10">
              <el-input
                v-model="pair[0]"
                placeholder="key"
                size="small"
                clearable
              />
            </el-col>
            <el-col :span="9" style="margin-left: 10px; margin-right: 20px">
              <el-input
                v-model="pair[1]"
                placeholder="value"
                size="small"
                clearable
              />
            </el-col>
            <el-button
              icon="el-icon-minus"
              @click="removePair(field, index)"
              style="display: inline-block"
              circle
            />
            <span
              v-if="errors[key][index] != null && errors[key][index] !== ''"
              style="color: #f56c6c; font-size: 0.6em"
              class="el-form-item__error"
            >
              {{ errors[key][index] }}
            </span>
          </el-form-item>
        </template>
      </template>
      <!-- bool -->
      <el-form-item
        v-else-if="TYPE_TO_INPUT_WIDGETS[field.Type] == FORM_WIDGETS.BOOL"
        :label="key"
        :prop="key"
      >
        <el-switch v-model="userInputDataForm[key].Value" />
      </el-form-item>
    </template>
  </el-form>
</template>

<script lang="ts">
import { QuestionFilled } from "@element-plus/icons-vue";
/* author: 范袁侨,
 * date: 2021/10/30
 */
// 后续还有choice部分，错误检验处理部分

import {
  DATA_TYPE_TO_INPUT_WIDGETS,
  FORM_WIDGETS,
  DATA_TYPE,
  FieldType,
  PropDataType,
  TransformDataToFields,
  pairsToObject,
  dateToTimestamp,
} from "./formdatastruct";
import {
  getFieldRules,
  FieldsValidation,
} from "@/components/dynamicform/formValidation";
import { deepCopy } from "./copy";
import { defineComponent, PropType } from "vue";
import { addOnNodeParamsChanged, emitNodeParamsChanged } from "../EventBus";

export default defineComponent({
  emits: ["data-changed"],
  components: {
    QuestionFilled,
  },
  props: {
    // props的类型提示可以参考这篇文章：https://blog.csdn.net/lgno2/article/details/109446711
    data: Object as PropType<Record<string, PropDataType>>,
  },

  data() {
    return {
      userInputDataForm: {} as Record<string, FieldType>, // a copy of fields
      TYPE_TO_INPUT_WIDGETS: DATA_TYPE_TO_INPUT_WIDGETS,
      FORM_WIDGETS: FORM_WIDGETS,
    };
  },

  computed: {
    fields(): Record<string, FieldType> {
      return TransformDataToFields(this.data!);
    },
    rules(): Record<string, Array<Record<string, unknown>>> {
      const rules: Record<string, Array<Record<string, unknown>>> = {};
      for (const key in this.data) {
        const fieldrules = getFieldRules(key, this.data[key]);
        if (fieldrules && fieldrules.length !== 0) {
          rules[key] = fieldrules;
        }
      }
      return rules;
    },
    userInputData(): Record<string, unknown> {
      const userInputData: Record<string, unknown> = {};
      for (const key in this.userInputDataForm) {
        let value: any = this.userInputDataForm[key].Value;

        const type = this.userInputDataForm[key].Type;
        switch (this.TYPE_TO_INPUT_WIDGETS[type]) {
          case FORM_WIDGETS.JSON:
            value = pairsToObject(value);
            break;
          case FORM_WIDGETS.DATETIME:
            if (value) {
              value = dateToTimestamp(value);
            }
            break;
          case FORM_WIDGETS.INPUT:
            if (
              type === DATA_TYPE.int ||
              type === DATA_TYPE.uint ||
              type === DATA_TYPE.float
            ) {
              value = value ? Number(value) : null;
            } else if (type === DATA_TYPE.signal) {
              try {
                value = eval(value);
              } catch (e) {
                console.error("cannot evalute the string:", value);
                throw e;
              }
            }
            break;
        }
        userInputData[key] = value;
      }
      return userInputData;
    },
    errors(): Record<string, (string | null)[]> {
      return FieldsValidation(this.userInputDataForm);
    },
  },

  methods: {
    // Type json add new key value in userInputDataForm
    // like: [['a', 1], ['b', 2]]
    addNewPair(field: FieldType): void {
      if (field.Value instanceof Array) {
        field.Value.push([null, null]);
      } else {
        field.Value = [[null, null]];
      }
    },
    removePair(field: FieldType, index: number): void {
      if (field.Value instanceof Array && index in field.Value) {
        field.Value.splice(index, 1);
      } else {
        throw Error(
          String(field.Value) +
            `\nfield.Value is not Array or index${index} is not in Array`
        );
      }
    },
    convertSignalToString() {
      for (const key in this.userInputDataForm) {
        if (this.userInputDataForm[key].Type === DATA_TYPE.signal) {
          this.userInputDataForm[key].Value = JSON.stringify(
            this.userInputDataForm[key].Value
          );
        }
      }
    },
  },
  watch: {
    userInputDataForm: {
      handler() {
        try {
          this.$emit("data-changed", this.userInputData);
        } catch (e) {
          console.error(e);
        }
      },
      deep: true,
    },
    data: {
      handler() {
        this.userInputDataForm = deepCopy(this.data!);
        this.convertSignalToString();
      },
      deep: true,
    },
  },
  created(): void {
    this.userInputDataForm = deepCopy(this.fields);
    this.convertSignalToString();
  },
});
</script>
<style>
.form-widget {
  margin-top: 6px;
  margin-bottom: 6px;
}

.form-widget .el-form-item {
  margin-bottom: 20px;
}
</style>
